package org.birtserver.backend.service.reports;

import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.birtserver.backend.dao.reports.ReportDao;
import org.birtserver.backend.model.Report;
import org.birtserver.backend.service.engine.Design;
import org.birtserver.backend.service.engine.EngineService;
import org.springframework.beans.factory.annotation.Required;

public class ReportServiceImpl implements ReportService {

  private ReportDao reportDao;
  
  private EngineService engineService;
  
  /**
   * Design catalog cache
   */
  private Map<Long, Design> designCatalog = new HashMap<Long, Design>();
  
  @Override
  public void createNewReport(Report report) {
    report.setLastUpdate(new Date());
    report.setId(System.currentTimeMillis());
    reportDao.createNewReport(report);
  }

  @Override
  public void deleteReport(long reportId) {
    reportDao.deleteReport(reportId);
  }

  @Override
  public List<Report> getAllReportNames() {
    return reportDao.getAllReportNames();
  }

  @Override
  public void updateReport(Report report) {
    report.setLastUpdate(new Date());
    if (report.getReport() == null) {
      Report previousReportState = reportDao.getCompleteReport(report.getId());
      report.setReport(previousReportState.getReport());
    }
    reportDao.updateReport(report);
  }
  
  private synchronized Design getActualDesign(Report report) {
    
    //try to find compiled design in cache
    Design design = designCatalog.get(report.getId());
    
    //if design was not in cache or is too old (newer version of design is availabe)
    //then compile design again
    if (design == null || 
        design.getCreatedTimestamp().before(report.getLastUpdate())) {
      
      design = engineService.loadDesign(new ByteArrayInputStream(report.getReport()));
      designCatalog.put(report.getId(), design);
      
    }
    
    return design;
    
  }
  
  @Override
  public void outputReportContent(long reportId, OutputStream outputStream) {
    
    Report report = reportDao.getCompleteReport(reportId);
    
    //try to find compiled design in cache
    Design design = getActualDesign(report);
     
    engineService.renderHTML(design, outputStream);
     
  }

  @Required
  public void setReportDao(ReportDao reportDao) {
    this.reportDao = reportDao;
  }
  
  @Required
  public void setEngineService(EngineService engineService) {
    this.engineService = engineService;
  }
  
}
